﻿using System;
using System.Xml;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Collections.Generic;
using gms.data;
using gms.system;

namespace gms.data {
	public static class OpcodeManager {
		public static XmlElement execute_code(string opcode, string arguments) {
			return null;
			/*
			XmlElement retval = null;
			Opcode exe_code = new Opcode();

			exe_code.load_full_by_name(opcode);

			// When attempting to load the opcode entry from the database
			// it returned null. Meaning no entry by that name. Meaning
			// that someone just tried loading something that the system
			// wasn't expecting to handle.
			if (exe_code.code_name == null) {
				throw new Exception("Unknown opcode submitted");
			}

			// Instead of waiting to see if the users submitted any arguments
			// we check to see if the opcode requires arguments. Then we check
			// to see if the user submitted arguments.
			if (exe_code.args != null) {
				if (arguments == null) {
					// Arguments requested by opcode, user didn't provide any. Slap their wrists!
					throw new Exception("Opcode requires arguments but none were provided");
				}
			}

			switch (exe_code.code_type) {
				case Opcode_Type.Procedure:
					retval = run_procedure(exe_code.code_execution, SqlExplosion(exe_code.args, arguments));
					break;
				case Opcode_Type.Class:
					retval = run_class(exe_code.code_execution, ListExplosion(exe_code.args, arguments));
					break;
			}

			return retval;
			*/
		}

		private static XmlElement run_procedure(string proc_name, SqlParameter[] arguments) {
			XmlDocument xdoc = new XmlDocument();
			XmlElement retval = xdoc.CreateElement("response");
			XmlElement temp_row;
			XmlElement temp_col;
			XmlAttribute temp_attr;

			DataSet builder = Database.exec_ds_return(proc_name, arguments);

			if (Database.dataset_is_empty(builder)) {
				retval.AppendChild(xdoc.CreateCDataSection("Query executed successfully"));
			}
			else {
				for (int i = 0; i < builder.Tables[0].Rows.Count; i++) {
					temp_attr = xdoc.CreateAttribute("num");
					temp_attr.Value = (i + 1).ToString();

					temp_row = xdoc.CreateElement("row");
					temp_row.Attributes.Append(temp_attr);

					for (int j = 0; j < builder.Tables[0].Columns.Count; j++) {
						temp_col = xdoc.CreateElement(builder.Tables[0].Columns[j].ColumnName);
						temp_col.AppendChild(xdoc.CreateCDataSection(builder.Tables[0].Rows[i][j].ToString()));

						temp_row.AppendChild(temp_col);
					}

					retval.AppendChild(temp_row);
				}
			}

			return retval;
		}
		private static XmlElement run_class(string execution_name, List<OpcodeArgument> arguments) {
			XmlDocument xdoc = new XmlDocument();
			XmlElement retval = xdoc.CreateElement("response");

			// Use reflection to load a class with a specified name, but
			// cast it as type IOpcode, because we will only run 1 of 2
			// methods it is contracted to have
			IOpcode executor = (IOpcode)Activator.CreateInstance(Type.GetType(execution_name));

			XmlElement return_value = null;

			if (arguments.Count != 0) {
				return_value = executor.ExecuteCode(arguments);
			}
			else {
				return_value = executor.ExecuteCode();
			}

			retval.AppendChild(xdoc.ImportNode(return_value, true));

			return retval;
		}

		private static SqlParameter[] SqlExplosion(string sys_argument_names, string provided_arguments) {
			SqlParameter[] retval = null;
			string[] sys_arg_seperator = { "," }; // System arguments (those in the table) are comma delimeted
			string[] arg_seperator = { "+" }; // Multiple arguments are separated like form query string elements
			string[] arg_sub_seperator = { "=" }; // Value assignment for an argument

			string[] split_args = provided_arguments.Split(arg_seperator, StringSplitOptions.RemoveEmptyEntries);
			string[] split_sub_arg;

			string[] sys_args = sys_argument_names.Split(sys_arg_seperator, StringSplitOptions.RemoveEmptyEntries);

			// First check, number of arguments in system must equal provided arguments
			if (sys_args.Length != split_args.Length) {
				throw new Exception("Opcode argument number of arguments mismatch");
			}

			retval = new SqlParameter[sys_args.Length];

			for (int i = 0; i < sys_args.Length; i++) {
				split_sub_arg = split_args[i].Split(arg_sub_seperator, StringSplitOptions.RemoveEmptyEntries);

				// Each argument must contain a key/value pair. If this dynamic
				// does not exist, then the request is incorrect
				if (split_sub_arg.Length != 2) {
					throw new Exception("Opcode argument number of values mismatch");
				}

				// If you cannot find mention of the key inside of the system arguments
				// then this is not a key/value pair you want. So we deny the entire
				// post because it could be tainted
				if (sys_argument_names.IndexOf(split_sub_arg[0]) == -1) {
					throw new Exception("Opcode argument was not expected");
				}

				retval[i] = new SqlParameter(split_sub_arg[0], split_sub_arg[1]);
			}

			// Okay, so not quite a 20 point inspection, but close enough!
			return retval;
		}
		private static List<OpcodeArgument> ListExplosion(string sys_argument_names, string provided_arguments) {
			List<OpcodeArgument> retval = new List<OpcodeArgument>();
			string[] sys_arg_seperator = { "," }; // System arguments (those in the table) are comma delimeted
			string[] arg_seperator = { "+" }; // Multiple arguments are separated like form query string elements
			string[] arg_sub_seperator = { "=" }; // Value assignment for an argument

			string[] split_args = provided_arguments.Split(arg_seperator, StringSplitOptions.RemoveEmptyEntries);
			string[] split_sub_arg;

			string[] sys_args = sys_argument_names.Split(sys_arg_seperator, StringSplitOptions.RemoveEmptyEntries);

			// First check, number of arguments in system must equal provided arguments
			if (sys_args.Length != split_args.Length) {
				throw new Exception("Opcode argument number of arguments mismatch");
			}

			for (int i = 0; i < sys_args.Length; i++) {
				split_sub_arg = split_args[i].Split(arg_sub_seperator, StringSplitOptions.RemoveEmptyEntries);

				// Each argument must contain a key/value pair. If this dynamic
				// does not exist, then the request is incorrect
				if (split_sub_arg.Length != 2) {
					throw new Exception("Opcode argument number of values mismatch");
				}

				// If you cannot find mention of the key inside of the system arguments
				// then this is not a key/value pair you want. So we deny the entire
				// post because it could be tainted
				if (sys_argument_names.IndexOf(split_sub_arg[0]) == -1) {
					throw new Exception("Opcode argument was not expected");
				}

				retval.Add(new OpcodeArgument(split_sub_arg[0], split_sub_arg[1]));
			}

			// Okay, so not quite a 20 point inspection, but close enough!
			return retval;
		}
	}
}